#ifndef __VEC3_H__
#define __VEC3_H__
#include "vec_core.h"

template <class T> class detail::Vec<T, 3> {
public:
    union {
        struct { T x, y, z; };
        struct { T r, g, b; };
        std::array<T, 3> data;
    };
    
    Vec() = default;
    Vec(const Vec&) = default;
    Vec(Vec&&) = default;
    Vec& operator = (const Vec&) = default;
    Vec& operator = (Vec&&) = default;

    Vec(std::initializer_list<T> il) {
        this->assign(il);
    }

    template <size_t Size2>
    Vec(const Vec<T, Size2>& other) {
        *this = other;
    }

    template <size_t Size2>
    Vec& operator = (const Vec<T, Size2>& other) {
        constexpr auto min = std::min((size_t)3, Size2);
        
        size_t i = 0;
        for ( ; i < min; ++i) {
            data[i] = other.data[i];
        }

        for ( ; i < 3; ++i) {
            data[i] = 0.0f;
        }

        return *this;
    }

    T& operator [] (size_t index) {
        return data[index];
    }

    T operator [] (size_t index) const {
        return data[index];
    }

    void assign(std::initializer_list<T> il) {
        auto min = std::min(il.size(), (size_t)3);
        
        size_t i = 0;
        for ( ; i < min; ++i) {
            data[i] = *(il.begin() + i);
        }
        for ( ; i < 3; ++i) {
            data[i] = 0;
        }
    }

    static Vec Zero() {
        return Vec{ 0.0f, 0.0f, 0.0f };
    }

    static Vec One() {
        return Vec{ 1.0f, 1.0f, 1.0f };
    }

    T length() const {
        return ::length(*this);
    }

    void normalize() {
        *this = ::normalize(*this);
    }

    using type = T;
    static constexpr size_t size = 3;
};

template <class T>
inline detail::Vec<T, 3> cross(const detail::Vec<T, 3>& v1, const detail::Vec<T, 3>& v2) {
    detail::Vec<T, 3> result;
    result.x = v1.y * v2.z - v1.z * v2.y;
    result.y = v1.z * v2.x - v1.x * v2.z;
    result.z = v1.x * v2.y - v1.y * v2.x;

    return result;
}

using Vec3f = detail::Vec<float, 3>;
using Vec3i = detail::Vec<std::int32_t, 3>;

using Normal3f = detail::Vec<float, 3>;
using Normal3i = detail::Vec<std::int32_t, 3>;

using Color3f = detail::Vec<float, 3>;
using Color3uc = detail::Vec<std::uint8_t, 3>;

#endif